package com.rizzo.analytics.services.web.controller.v1;

import com.mangofactory.swagger.annotations.ApiErrors;
import com.mangofactory.swagger.annotations.ApiModel;
import com.rizzo.analytics.domain.account.Account;
import com.rizzo.analytics.domain.errors.Errors;
import com.rizzo.analytics.services.web.controller.v1.error.ErrorsNotFoundException;
import com.rizzo.analytics.services.web.controller.v1.error.ValidationException;
import com.rizzo.infrastructure.dark.DarkLaunch;
import com.rizzo.infrastructure.performance.Monitor;
import com.rizzo.infrastructure.quota.Quota;
import com.rizzo.infrastructure.web.validator.Save;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiError;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

// TODO when application was not found throw 404 exception for API consistency

@Controller("errorController")
@RequestMapping(value = "/error", produces = "application/json")
@Api(value = "/error", description = "Operations about errors")
public class ErrorController extends RizzoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ErrorController.class);

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @Quota(maxCalls = 1000, expireSeconds = 86400)
    @DarkLaunch(name = "get-errors")
    @RequestMapping(value = "/{application}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "Lists the error data",
            notes = "Returns all the occured errors for a given application. " +
                    "This endpoint can only be called when logged in and will only return the " + PAGE_SIZE + " first entries!",
            responseClass = "com.rizzo.analytics.domain.errors.Errors", tags = "error")
    @ApiErrors({ErrorsNotFoundException.class})
    @com.wordnik.swagger.annotations.ApiErrors(
            {@ApiError(code = 404, reason = "Quota exceeded"),
                    @ApiError(code = 404, reason = "Not available")}
    )
    @ApiModel(type = Errors.class)
    public Errors getErrors(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application " +
                            "(see output of '/application' for possible values)") String application) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Querying errors for [application: '{}'] and [user : '{}']", application, user);
        return analyticsDelegator.getErrors(user, application, WILDCARD, Integer.parseInt(PAGE_SIZE), 0);
    }

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @Quota(maxCalls = 10000, expireSeconds = 86400)
    @DarkLaunch(name = "save-errors")
    @RequestMapping(value = "/{application}", method = RequestMethod.POST, produces = "application/json")
    @ApiOperation(value = "Save error data",
            notes = "Save all the occured errors for a given application. " +
                    "This endpoint can only be called when logged in!",
            tags = "error,save")
    @ApiErrors({ValidationException.class})
    @com.wordnik.swagger.annotations.ApiErrors(
            {@ApiError(code = 404, reason = "Quota exceeded"),
                    @ApiError(code = 404, reason = "Not available")}
    )
    public void saveErrors(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application " +
                            "(see output of '/application' for possible values or a new one!)") String application,
            @RequestBody
            @Validated(Save.class)
            @ApiParam(name = "errors", required = true,
                    value = "The errors to save")
            @ApiModel(type = Errors.class) Errors errors) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Saving errors for [application: '{}'] with [user : '{}']", application, user);
        analyticsDelegator.saveErrors(user, application, errors);
    }

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @Quota(maxCalls = 1000, expireSeconds = 86400)
    @DarkLaunch(name = "get-errors-with-criteria")
    @RequestMapping(value = "/{application}/{code}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "List of the pageable error data",
            notes = "Returns all the occured errors for a given application. " +
                    "Results from this endpoint are pageable/sortable and can be filtered by code. " +
                    "This endpoint can only be called when logged in!",
            responseClass = "com.rizzo.analytics.domain.errors.Errors", tags = "error,paged")
    @ApiErrors({ErrorsNotFoundException.class})
    @com.wordnik.swagger.annotations.ApiErrors(
            {@ApiError(code = 404, reason = "Quota exceeded"),
                    @ApiError(code = 404, reason = "Not available")}
    )
    @ApiModel(type = Errors.class)
    public Errors getErrorsWithCriteria(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application " +
                            "(see output of '/application' for possible values)") String application,
            @PathVariable("code")
            @ApiParam(name = "code", required = true, defaultValue = "*",
                    value = "The code of the error (wildcards '*' are allowed, see '/info' for possible values)") String code,
            @RequestParam(value = "limit", required = false, defaultValue = PAGE_SIZE)
            @ApiParam(name = "limit", required = false, defaultValue = PAGE_SIZE,
                    allowableValues = ERROR_PAGE_LIMIT_RANGE,
                    value = "The page-size/limit of the results") long limit,
            @RequestParam(value = "offset", defaultValue = "0", required = false)
            @ApiParam(name = "offset", defaultValue = "0", required = false,
                    value = "The page-offset of the results") long offset) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        validatePaging(limit, offset, ERROR_PAGE_LIMIT_RANGE);
        LOGGER.debug("Querying errors for [application: '{}'] and [user : '{}'] with [code : '{}']", application, user, code);
        return analyticsDelegator.getErrors(user, application, code, limit, offset);
    }

}
